#ifndef DIGEST_H_INCLUDED
#define DIGEST_H_INCLUDED

#define MAX_DIGEST_LENGTH 20

#include "Typedef.h"
#include "Log.h"

#define BOOK_DATA_LENGTH_FOR_MAKING_DIGEST 1024

class Digest
{
public:
    Digest(){};
    virtual ~Digest(){};

    virtual BPcode MakeDigest(Bupchar data, uint32_t datalen){return BP_BAD;};
    virtual BPcode CopyDigestBinary(Bupchar out, uint32_t* outlen){return BP_BAD;};
    virtual BPcode CopyDigestHex(Bpchar out, uint32_t* outlen){return BP_BAD;};

    Bupchar GetDigestBinary(){return (Bupchar)digest_bin;}
    Bpchar GetDigestHex(){return (Bpchar)digest_hex;}

public:
    Buchar digest_bin[MAX_DIGEST_LENGTH];
    uint32_t digest_bin_len;
    Bchar digest_hex[MAX_DIGEST_LENGTH*2+1];
};

/* UINT4 defines a four byte word */
typedef unsigned int UINT4;

/* MD5 context. */
struct md5_ctx {
  UINT4 state[4];                                   /* state (ABCD) */
  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
  unsigned char buffer[64];                         /* input buffer */
};

class MD5 : public Digest
{
public:
    MD5();
    ~MD5();

    virtual BPcode MakeDigest(Bupchar data, uint32_t datalen);
    virtual BPcode CopyDigestBinary(Bupchar out, uint32_t* outlen);
    virtual BPcode CopyDigestHex(Bpchar out, uint32_t* outlen);

private:
    void MD5_Init();
    void MD5_Update(const unsigned char *, unsigned int);
    void MD5_Final(unsigned char[16]);
    void MD5Transform(UINT4 state[4], const unsigned char block[64]);
    void Encode (unsigned char *output, UINT4 *input, unsigned int len);
    void Decode (UINT4 *output, const unsigned char *input, unsigned int len);

    md5_ctx* Context;
};

#endif // DIGEST_H_INCLUDED
